;; **********************************************************************
;;                           circuit.clp
;;
;; For the course Reasoning with Computer Support: an example 
;; that illustrates inheritance and a logic circuit in JESS
;;
;; Based on circuit.clp by Peter Lucas
;;
;; Arjen Hommersom, October 2010
;;
;; **********************************************************************

(require create-gui "circuitgui.clp")

;; ******************************
;; DEFTEMPLATES

;; each gate has at least 1 input and an output
(deftemplate GATE
	(slot name)
	(slot in1)
	(slot out))

;; the IDGATE outputs the input
(deftemplate IDGATE extends GATE)

(deftemplate INPUT extends IDGATE)

(deftemplate OUTPUT extends IDGATE)

(deftemplate ANDGATE extends GATE 
	(slot in2))

(deftemplate XORGATE extends GATE
	(slot in2))

(deftemplate WIRE
	(slot from)
	(slot to-port)
	(slot of-gate))

;; ******************************
;; DEFFACTS

(deffacts circuit
	(ANDGATE (name "A"))
	(XORGATE (name "X"))
	(INPUT (name "I1"))
	(INPUT (name "I2"))
	(INPUT (name "I3"))
	(OUTPUT (name "O1"))
	(OUTPUT (name "O2"))
	(WIRE (from "I1") (to-port "in1") (of-gate "X"))
	(WIRE (from "I2") (to-port "in2") (of-gate "X"))
	(WIRE (from "X") (to-port "in1") (of-gate "A"))
	(WIRE (from "I3") (to-port "in2") (of-gate "A"))
	(WIRE (from "X") (to-port "in1") (of-gate "O1"))
	(WIRE (from "A") (to-port "in1") (of-gate "O2"))
)

;; ******************************
;; DEFRULES

;; these rules create the interface between the GUI and the circuit

(defrule init
    ;; if there are GUIinputs in the fact base, put them
    ;; in the INPUT gates and retract the GUIinputs
    ?g <- (GUIinputs (in1 ?i1) (in2 ?i2) (in3 ?i3))
    ?I1 <- (INPUT (name "I1"))
    ?I2 <- (INPUT (name "I2"))
    ?I3 <- (INPUT (name "I3"))
  =>
    (modify ?I1 (in1 ?i1))
    (modify ?I2 (in1 ?i2))
    (modify ?I3 (in1 ?i3))
    (retract ?g))

(defrule store-output
    ;;store the output value in a variable outputvalue
    (OUTPUT (name ?name) (out ?o))
  =>
    (store ?name ?o))

;; behaviour of circuit

(defrule propagate-andgate-1
    "propagation rule 1 for AND gates"
    ?gate <- (ANDGATE (in1 ?x&:(neq ?x nil)) (in2 ?x))
  =>
    (modify ?gate (out ?x)))

(defrule propagate-andgate-2
    "propagation rule 2 for AND gates"
    ?gate <- (ANDGATE (in1 ?x&:(neq ?x nil))
                      (in2 ?y&:(and (neq ?y nil) (neq ?x ?y))))
  =>
    (modify ?gate (out 0)))

(defrule propagate-xorgate-1
	 "propagation rule 1 for XOR gates"
	 ?gate <- (XORGATE (in1 ?x &: (neq ?x nil))
			   (in2 ?y &: (and (neq ?y nil) (neq ?x ?y))))
	 =>
	 (modify ?gate (out 1)))

(defrule propagate-xorgate-0
	 "propagation rule 0 for XOR gates"
	 ?gate <- (XORGATE (in1 ?x &: (neq ?x nil))
			   (in2 ?y &: (and (neq ?y nil) (eq ?x ?y))))
	 =>
	 (modify ?gate (out 0)))

(defrule propagate-idgate
    "propagation rule for IDGATES"
    ?gate <- (IDGATE (in1 ?x&:(neq ?x nil)))
  =>
    (modify ?gate (out ?x)))

(defrule propagate-to-gate
    "propagation rule to propagate input to port"
    (WIRE (from ?f) (to-port ?port) (of-gate ?inst))
    ;; prevent propagation of nil which causes this rule never to be
    ;; re-activated
    (GATE (name ?f) (out ?x &:(neq ?x nil)))
    ?gate <- (GATE (name ?inst))
  =>
    (modify ?gate (?port ?x)))


;; ******************************
;; Run the program

(reset)
(create-gui)

;; **********************************************************************
